---
title: Mutations (experimental)
---
import { Link } from "/src/components/Link";
import CodeBlock from "@theme/CodeBlock";
import { trimSnippet } from "/src/components/CodeSnippet";
import listener from 'raw-loader!./mutations/listening.dart';
import keyed from 'raw-loader!./mutations/keyed.dart';
import generic from 'raw-loader!./mutations/generic.dart';
import triggering from 'raw-loader!./mutations/triggering.dart';
import switching from 'raw-loader!./mutations/switching.dart';
import resetting from 'raw-loader!./mutations/resetting.dart';

:::caution
Mutations are experimental, and the API may change in a breaking way without
a major version bump.
:::

Mutations, in Riverpod, are objects which enable the user interface
to react to state changes.
A common use-case is displaying a loading indicator while a form is being submitted

In short, mutations are to achieve effects such as this:
![Submit progress indicator](/img/concepts2/mutations/spinner.gif)!

Without mutations, you would have to store the progress of the form submission
directly inside the state of a provider. This is not ideal as it pollutes the
state of your provider with UI concerns ; and it involves a lot of boilerplate code
to handle the loading state, error state, and success state.

Mutations are designed to handle these concerns in a more elegant way.

## Defining a mutation

Mutations are instances of the [Mutation] object, stored in a final variable somewhere.

```dart
// A mutation to track the "add todo" operation.
// The generic type is optional and can be specified to enable the UI to interact
// with the result of the mutation.
final addTodo = Mutation<Todo>();
```

:::note
Typically, this variable will either be global or as a `static final` variable on
a [Notifier].
:::

## Listening to a mutation

Once we've defined a mutation, we can start using it inside <Link documentID="concepts2/consumers" /> or <Link documentID="concepts2/providers" />.  
For this, we will need a <Link documentID="concepts2/refs" /> and pick a listening method of our choice
(typically [Ref.watch]).

A typical example would be:

<CodeBlock>{trimSnippet(listener)}</CodeBlock>

### Scoping a mutation

Sometimes, you may want to have multiple instances of the same mutation.

This can include things like an id, or any other parameter that makes the mutation unique.

This is useful if you want to have multiple instances of the same mutation,
such as deleting a specific item in a list

Simply call the mutation with the unique key:

<CodeBlock>{trimSnippet(keyed)}</CodeBlock>

Sometimes, these mutations have a generic return type,
such as if an api response may have different response types
based on the input parameters, such as with deserialization.

<CodeBlock>{trimSnippet(generic)}</CodeBlock>

### Triggering a mutation

So far, we've listened to the state of a mutation, but nothing actually happens yet.

To trigger a mutation, we can use [Mutation.run], pass our mutation, and provide an asynchronous callback
that updates whatever state we want. Lastly, we'll need to return a value matching the generic type of the mutation.

<CodeBlock>{trimSnippet(triggering)}</CodeBlock>

### The different mutation states and their meaning

Mutations can be in one of the following states:
- [MutationPending]: The mutation has started and is currently loading.
- [MutationError]: The mutation has failed, and an error is available.
- [MutationSuccess]: The mutation has succeeded, and the result is available.
- [MutationIdle]: The mutation has not been called yet, or has been reset.

You can switch over the different states using a `switch` statement:

<CodeBlock>{trimSnippet(switching)}</CodeBlock>

### After a mutation has been started once, how to reset it to its idle state?

Mutations naturally reset themselves to [MutationIdle] if:
- They have completed (either successfully or with an error).
- All listeners have been removed (e.g. the spinner widget has been removed)

This is similar to how <Link documentID="concepts2/auto_dispose"/> works, but for mutations.

Alternatively, you can manually reset a mutation to its idle state
by calling the [Mutation.reset] method:

<CodeBlock>{trimSnippet(resetting)}</CodeBlock>

[MutationPending]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationPending-class.html
[MutationError]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationError-class.html
[MutationSuccess]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationSuccess-class.html
[MutationIdle]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationIdle-class.html
[Mutation.reset]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation/reset.html
[Mutation.run]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation/run.html
[Mutation]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation-class.html
[Notifier]: https://pub.dev/documentation/riverpod/latest/riverpod/Notifier-class.html
[Ref.watch]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/watch.html